/*
**  Copyright (c) 2014 Michael Liu(michael.liu.point@gmail.com).
**
**  Project: Gateway Unified Management Platform
**  File:      dpifopt.c
**  Author:  Michael
**  Date:    03/20/2014
**
**  Purpose:
**    data path interface common method implement.
*/

/* Include files. */

#include "dpmgr.h"
#include "svcmgr.h"
#include "osdep.h"
#include "pfdep.h"

/* Macro constant definitions. */

/* Type definitions. */

/* Local function declarations. */

static e_ret dpif_do_static_netcfg(tdp_if * dp_if, tstatic_netcfg * static_cfg);
static e_ret dpif_do_dhcp_netcfg(tdp_if * dp_if, e_bool manual_dns);

static e_ret dhcpc_svc_start(tsm_svc * svc);
static e_ret dpif_add_dhcpc_svc(tdp_if * dp_if);
static e_ret dpif_del_dhcpc_svc(tdp_if * dp_if);

static void dpif_reload_dhcpd_and_dns(tdp_if * dp_if);

/* Macro API definitions. */

/* Global variable declarations. */

e_bool is_valid_ip(const char *ipaddr)
{
	return (os_dep_is_valid_ip(ipaddr));
}

e_bool is_valid_netmask(const char *netmask)
{
	unsigned int b = 0, i, n[4];

	if (os_dep_is_valid_ip(netmask)) {
		sscanf(netmask, "%u.%u.%u.%u", &n[3], &n[2], &n[1], &n[0]);
		for (i = 0; i < 4; ++i) {
			b += n[i] << (i * 8);
		}
		b = ~b + 1;
		if ((b & (b - 1)) == 0) {
			return eBOOL_TRUE;
		}
	}

	return eBOOL_FALSE;
}

e_ret dpif_getlinkcfg_common(tdp_if * dp_if, void **linkcfg, int *size, tmask * mask)
{

	void *cfg_buf;

	sysmgr_trace_enter();
	if (!mask_test_bit(dp_if->attr, eDP_IF_ATTR_LINK) || (dp_if->linkcfg_size == 0)) {
		*size = 0;
		sysmgr_dbg("if[%s], attr: 0x%08X, linkcfg_size: %d\n", dp_if->name, dp_if->attr, dp_if->linkcfg_size);
		sysmgr_trace_exit();
		return (eRET_INVALID_STATE);
	}

	if ((*size < dp_if->linkcfg_size) || (*linkcfg == NULL)) {
		cfg_buf = malloc(dp_if->linkcfg_size);
		if (cfg_buf == NULL) {
			sysmgr_err("malloc(%d) failed, err: %d,[%s]\n", dp_if->linkcfg_size, errno, strerror(errno));
			*size = 0;
			sysmgr_trace_exit();
			return (eRET_NO_RESOURCE);
		}
		*linkcfg = cfg_buf;
	} else {
		cfg_buf = *linkcfg;
	}

	*size = dp_if->linkcfg_size;

	memcpy(cfg_buf, dp_if->linkcfg, dp_if->linkcfg_size);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);
}

e_ret dpif_getnetcfg_common(tdp_if * dp_if, void **netcfg, int *size, tmask * mask)
{

	void *cfg_buf;

	sysmgr_trace_enter();
	if (!mask_test_bit(dp_if->attr, eDP_IF_ATTR_NET) || (dp_if->netcfg_size == 0)) {
		*size = 0;
		sysmgr_dbg("if[%s], attr: 0x%08X, netcfg_size: %d\n", dp_if->name, dp_if->attr, dp_if->netcfg_size);
		sysmgr_trace_exit();
		return (eRET_INVALID_STATE);
	}

	if ((*size < dp_if->netcfg_size) || (*netcfg == NULL)) {
		cfg_buf = malloc(dp_if->netcfg_size);
		if (cfg_buf == NULL) {
			sysmgr_err("malloc(%d) failed, err: %d,[%s]\n", dp_if->netcfg_size, errno, strerror(errno));
			*size = 0;
			sysmgr_trace_exit();
			return (eRET_NO_RESOURCE);
		}
		*netcfg = cfg_buf;
	} else {
		cfg_buf = *netcfg;
	}

	*size = dp_if->netcfg_size;

	memcpy(cfg_buf, dp_if->netcfg, dp_if->netcfg_size);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);
}

e_ret dpif_setnetcfg_common(tdp_if * dp_if, void *netcfg, tmask * mask)
{

	tdp_if_netcfg *if_netcfg;
	tdp_if_netcfg *new_netcfg;

	sysmgr_trace_enter();

	if (!mask_test_bit(dp_if->attr, eDP_IF_ATTR_NET)) {
		memset(mask, 0, sizeof(*mask));
		sysmgr_trace_exit();
		return (eRET_INVALID_STATE);
	}

	if ((!mask_test_bitmask(mask->mask[0], eDP_IF_NETCFG_MASK0_ALL)) &&
	    (!mask_test_bitmask(mask->mask[1], eDP_IF_NETCFG_MASK0_ALL))) {
		/* No update */
		sysmgr_trace_exit();
		return (eRET_SUCCESS);
	}

	if (dp_if->netcfg == NULL) {
		if_netcfg = malloc(sizeof(*if_netcfg));
		if (if_netcfg == NULL) {
			sysmgr_err("malloc(%d) failed, err: %d,[%s]\n", sizeof(*if_netcfg), errno, strerror(errno));
			sysmgr_trace_exit();
			return (eRET_NO_RESOURCE);
		}
		memset(if_netcfg, 0, sizeof(*if_netcfg));
		dp_if->netcfg = if_netcfg;
		dp_if->netcfg_size = sizeof(*if_netcfg);
	} else {
		if_netcfg = (tdp_if_netcfg *) dp_if->netcfg;
	}

	new_netcfg = (tdp_if_netcfg *) netcfg;

	if (mask_test_bit(mask->mask[0], eDP_IF_NETCFG_MASK0_CONNTYPE)) {
		if_netcfg->conntype = new_netcfg->conntype;
		pf_dep_set_if_netcfg_conntype(dp_if, if_netcfg->conntype);
	}

	switch (if_netcfg->conntype) {
	case eDP_IF_CONN_TYPE_PPTP:
		return (eRET_NOT_SUPPORT);
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPTP_USERNAME)) {
			str_safe_cpy(if_netcfg->pptp_conn.username, new_netcfg->pptp_conn.username, USERNAME_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPTP_PASSWORD)) {
			str_safe_cpy(if_netcfg->pptp_conn.password, new_netcfg->pptp_conn.password, PASSWORD_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPTP_SERVERIP)) {
			str_safe_cpy(if_netcfg->pptp_conn.serverip,
				     new_netcfg->pptp_conn.serverip, RC_IPV4_STR_MAX_SIZE - 1);
		}
		pf_dep_set_if_netcfg_pptp(dp_if, &if_netcfg->pptp_conn);
		break;

	case eDP_IF_CONN_TYPE_PPPOE:
		return (eRET_NOT_SUPPORT);
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPPOE_USERNAME)) {
			str_safe_cpy(if_netcfg->pppoe_conn.username,
				     new_netcfg->pppoe_conn.username, USERNAME_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPPOE_PASSWORD)) {
			str_safe_cpy(if_netcfg->pppoe_conn.password,
				     new_netcfg->pppoe_conn.password, PASSWORD_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_PPPOE_CONNTYPE)) {
			if_netcfg->pppoe_conn.conntype = new_netcfg->pppoe_conn.conntype;
		}
		pf_dep_set_if_netcfg_pppoe(dp_if, &if_netcfg->pppoe_conn);
		break;

	case eDP_IF_CONN_TYPE_PPP:
		return (eRET_NOT_SUPPORT);
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_MODEM_DIALNUM)) {
			str_safe_cpy(if_netcfg->modem_conn.dialnumber, new_netcfg->modem_conn.dialnumber, 16 - 1);
		}
		pf_dep_set_if_netcfg_ppp(dp_if, &if_netcfg->modem_conn);
		break;

	case eDP_IF_CONN_TYPE_DHCP:
		break;

	case eDP_IF_CONN_TYPE_STATIC:
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_STATIC_IPADDR)) {
			str_safe_cpy(if_netcfg->static_conn.ipaddr,
				     new_netcfg->static_conn.ipaddr, RC_IPV4_STR_MAX_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_STATIC_NETMASK)) {
			str_safe_cpy(if_netcfg->static_conn.netmask,
				     new_netcfg->static_conn.netmask, RC_IPV4_STR_MAX_SIZE - 1);
		}
		if (mask_test_bit(mask->mask[1], eDP_IF_NETCFG_MASK1_STATIC_DEFAULTGW)) {
			str_safe_cpy(if_netcfg->static_conn.defaultgw,
				     new_netcfg->static_conn.defaultgw, RC_IPV4_STR_MAX_SIZE - 1);
		}
		pf_dep_set_if_netcfg_static(dp_if, &if_netcfg->static_conn);
		break;

	case eDP_IF_CONN_TYPE_NONE:
		break;

	default:
		return (eRET_INVALID_ARG);
	}

	if (mask_test_bit(mask->mask[0], eDP_IF_NETCFG_MASK0_MTU)) {
		if_netcfg->mtu = new_netcfg->mtu;
		pf_dep_set_if_netcfg_mtu(dp_if, if_netcfg->mtu);
	}

	if (mask_test_bit(mask->mask[0], eDP_IF_NETCFG_MASK0_MANUAL_DNS)) {
		if_netcfg->man_dns = new_netcfg->man_dns;
		if (if_netcfg->man_dns) {
			memcpy(&if_netcfg->dns, &new_netcfg->dns, sizeof(if_netcfg->dns));
			os_dep_update_name_server(if_netcfg->dns.dns1, if_netcfg->dns.dns2);
		}
		pf_dep_set_if_netcfg_dns(dp_if, if_netcfg->man_dns, &if_netcfg->dns);
	}

	if (mask_test_bit(mask->mask[0], eDP_IF_NETCFG_MASK0_DHCPD)) {
		if (new_netcfg->dhcpd_cfg.dhcpd_type == eDP_IF_DHCPD_TYPE_ENABLE) {
			memcpy(&if_netcfg->dhcpd_cfg, &new_netcfg->dhcpd_cfg, sizeof(new_netcfg->dhcpd_cfg));
		} else {
			if_netcfg->dhcpd_cfg.dhcpd_type = new_netcfg->dhcpd_cfg.dhcpd_type;
		}
		pf_dep_set_if_netcfg_dhdpd(dp_if, &if_netcfg->dhcpd_cfg);
	}

	sysmgr_trace_exit();
	return (eRET_SUCCESS);

}

e_ret dpif_connect_common(tdp_if * dp_if)
{

	e_ret ret;
	tdp_if_netcfg *if_netcfg;

	sysmgr_trace_enter();

	if ((!mask_test_bit(dp_if->attr, eDP_IF_ATTR_NET)) || (dp_if->netcfg_size == 0) || (dp_if->netcfg == NULL)) {
		sysmgr_trace_exit();
		return (eRET_INVALID_STATE);
	}

	if_netcfg = dp_if->netcfg;

	switch (if_netcfg->conntype) {
	case eDP_IF_CONN_TYPE_PPTP:
	case eDP_IF_CONN_TYPE_PPPOE:
	case eDP_IF_CONN_TYPE_PPP:
		//dpif_do_dhcp_netcfg(dp_if, eBOOL_FALSE);
		ret = eRET_NOT_SUPPORT;
		break;

	case eDP_IF_CONN_TYPE_DHCP:
		ret = dpif_do_dhcp_netcfg(dp_if, eBOOL_TRUE);
		break;

	case eDP_IF_CONN_TYPE_STATIC:
		dpif_do_dhcp_netcfg(dp_if, eBOOL_FALSE);
		ret = dpif_do_static_netcfg(dp_if, &if_netcfg->static_conn);
		break;

	case eDP_IF_CONN_TYPE_NONE:
		dpif_do_dhcp_netcfg(dp_if, eBOOL_FALSE);
		ret = eRET_SUCCESS;
		break;

	default:
		ret = eRET_INVALID_ARG;
		break;
	}

	os_dep_set_if_mtu(dp_if->name, if_netcfg->mtu);

	dpif_update_dhcpd_cfg(dp_if);

	dpif_reload_dhcpd_and_dns(dp_if);

	sysmgr_trace_exit();
	return (ret);
}

void check_udhcpc_action(tdp_if * dp_if, unsigned char *need_dhcpd)
{

	char dhcpc_action_file[64];
	char action_buf[64];
	int fd;
	int rc;

	if (!dp_if) {
		*need_dhcpd = eBOOL_FALSE;
		return;
	}

	sprintf(dhcpc_action_file, "/tmp/udhcpc_%s.action", dp_if->name);

	fd = open(dhcpc_action_file, O_RDONLY);
	if (fd < 0) {
		sysmgr_info("open(%s) failed, err: %d,[%s]\n", dhcpc_action_file, errno, strerror(errno));
		*need_dhcpd = eBOOL_FALSE;
		return;
	}

	memset(action_buf, 0, sizeof(action_buf));
	rc = read(fd, action_buf, sizeof(action_buf));
	if (rc < 0) {
		sysmgr_info("read(%d) failed, err: %d, [%s]\n", fd, errno, strerror(errno));
		*need_dhcpd = eBOOL_FALSE;
		return;
	}

	sysmgr_info("udhcpc %s action[%s]\n", dp_if->name, action_buf);

	if ((strcmp(action_buf, "renew") == 0) || (strcmp(action_buf, "bound") == 0)) {
		*need_dhcpd = eBOOL_FALSE;
	} else {
		*need_dhcpd = eBOOL_TRUE;
	}

}

e_ret dpif_update_dhcpd_cfg(tdp_if * dp_if)
{
	e_ret ret;
	int rc;
	int fd, hosts_fd;
	int netstatus_size;
	tdhcpd_cfg *dhcpd_cfg;
	unsigned char dhcpd_type;
	tdp_if_netcfg *if_netcfg;
	char dhcpd_cfg_buf[256];
	tdp_if_netstatus *netstatus;
	unsigned int ipaddr[4];
	unsigned char need_dhcpd;

	sysmgr_trace_enter();

	hosts_fd = open(DNSMASQ_DHCPD_HOSTS_CONF_FILE, O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0666);
	if (hosts_fd < 0) {
		sysmgr_err("open(%s) failed, err: %d,[%s]\n", DNSMASQ_DHCPD_HOSTS_CONF_FILE, errno, strerror(errno));
		return (eRET_FAILURE);
	}
	/*
	 ** There is nothing in this file now.
	 ** This file is used to manager static dhcp lease by MAC.
	 */
	write(hosts_fd, "\n", 1);
	close(hosts_fd);

	fd = open(DNSMASQ_DHCPD_CONF_FILE, O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0666);
	if (fd < 0) {
		sysmgr_err("open(%s) failed, err: %d,[%s]\n", DNSMASQ_DHCPD_CONF_FILE, errno, strerror(errno));
		return (eRET_FAILURE);
	}

	dhcpd_cfg = NULL;
	if (dp_if != NULL) {
		if_netcfg = (tdp_if_netcfg *) dp_if->netcfg;
		if (if_netcfg != NULL) {
			dhcpd_cfg = &if_netcfg->dhcpd_cfg;
			dhcpd_type = dhcpd_cfg->dhcpd_type;
		} else {
			sysmgr_dbg("if[%s], got NULL net config.\n", dp_if->name);
		}
	} else {
		sysmgr_dbg("Get NULL dp interface pointer.\n");
	}

	if (dhcpd_cfg == NULL) {
		dhcpd_type = eDP_IF_DHCPD_TYPE_DISABLE;
	}

	switch (dhcpd_type) {
	case eDP_IF_DHCPD_TYPE_SMART:
		check_udhcpc_action(dp_if, &need_dhcpd);
		if (need_dhcpd) {
			/* prepare dhcp config */
			ret = dpif_getnetstatus_common(dp_if, &netstatus, &netstatus_size);
			if ((ret != eRET_SUCCESS) || (netstatus == NULL)) {
				sysmgr_err("dpif_getnetstatus_common() failed, ret: %d.\n", ret);
				/* empty the file content */
				write(fd, "\n", 1);
				break;
			}

			dhcpd_cfg->lease = 60;
			sscanf(netstatus->ipaddr, "%d.%d.%d.%d", &ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3]);

			sprintf(dhcpd_cfg->start, "%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], 100);
			sprintf(dhcpd_cfg->end, "%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], 200);
			str_safe_cpy(dhcpd_cfg->netmask, netstatus->netmask, RC_IPV4_STR_MAX_SIZE - 1);
			str_safe_cpy(dhcpd_cfg->defaultgw, netstatus->ipaddr, RC_IPV4_STR_MAX_SIZE - 1);
			str_safe_cpy(dhcpd_cfg->dns.dns1, netstatus->ipaddr, RC_IPV4_STR_MAX_SIZE - 1);
			memset(dhcpd_cfg->dns.dns2, 0, sizeof(dhcpd_cfg->dns.dns2));
			//rc = sprintf(dhcpd_cfg_buf, "dhcp-delay\n");
			//write(fd, dhcpd_cfg_buf, rc);

			free(netstatus);
			/* do NOT break here. */
		} else {
			/* empty the file content */
			write(fd, "\n", 1);
			break;
		}

	case eDP_IF_DHCPD_TYPE_ENABLE:
		rc = sprintf(dhcpd_cfg_buf, "interface=%s\n", dp_if->name);
		write(fd, dhcpd_cfg_buf, rc);
		rc = sprintf(dhcpd_cfg_buf, "dhcp-range=%s,%s,%s,%lus\n",
			     dhcpd_cfg->start, dhcpd_cfg->end, dhcpd_cfg->netmask, dhcpd_cfg->lease);
		write(fd, dhcpd_cfg_buf, rc);
		/* default router */
		rc = sprintf(dhcpd_cfg_buf, "dhcp-option=3,%s\n", dhcpd_cfg->defaultgw);
		write(fd, dhcpd_cfg_buf, rc);
		/* name server */
		rc = sprintf(dhcpd_cfg_buf, "dhcp-option=6,%s\n", dhcpd_cfg->dns.dns1);
		write(fd, dhcpd_cfg_buf, rc);
		rc = sprintf(dhcpd_cfg_buf, "dhcp-leasefile=/tmp/dnsmasq.leases\n");
		write(fd, dhcpd_cfg_buf, rc);
		break;

	case eDP_IF_DHCPD_TYPE_DISABLE:
		/* empty the file content */
		write(fd, "\n", 1);
		break;
	}

	close(fd);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);

}

void dpif_reload_dhcpd_and_dns(tdp_if * dp_if)
{
	tsm_svc *dnsmasq;
	tdnsmasq_svc_priv *priv;

	dpif_update_dns_addr_cfg(NULL);

	svcmgr_find_svc(SYSMGR_SVC_DNSMASQ, &dnsmasq);
	if (dnsmasq != NULL) {
		priv = dnsmasq->priv;
		priv->dp = (void *)dp_if->data_paths;
		priv->dp_if = (void *)dp_if;
		if (dnsmasq->reload != NULL) {
			dnsmasq->reload(dnsmasq);
		}
	} else {
		sysmgr_err("!!!!!! Dnsmasq do NOT exist !!!!!!\n");
	}

}

e_ret dpif_do_dhcp_netcfg(tdp_if * dp_if, e_bool start)
{

	sysmgr_trace_enter();

	if (start) {
		dpif_add_dhcpc_svc(dp_if);
	} else {
		dpif_del_dhcpc_svc(dp_if);
	}

	sysmgr_trace_exit();

	return (eRET_SUCCESS);
}

e_ret dpif_do_static_netcfg(tdp_if * dp_if, tstatic_netcfg * static_cfg)
{
	e_ret ret;

	sysmgr_trace_enter();
	if (!(is_valid_ip(static_cfg->ipaddr) &&
	      is_valid_ip(static_cfg->defaultgw) && is_valid_netmask(static_cfg->netmask))) {
		sysmgr_err("Invalid static net config.\n");
		ret = eRET_INVALID_ARG;
		goto out;
	}

	ret = os_dep_set_if_ipaddr(dp_if->name, static_cfg->ipaddr);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_set_if_ipaddr() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_set_if_netmask(dp_if->name, static_cfg->netmask);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_set_if_netmask() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_change_default_gw(static_cfg->defaultgw);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_change_default_gw() failed, ret: %d\n", ret);
		goto out;
	}

out:

	sysmgr_trace_exit();
	return (ret);
}

e_ret dpif_getnetstatus_common(tdp_if * dp_if, tdp_if_netstatus ** netstatus, int *netstatus_size)
{
	e_ret ret;
	int status_size;
	tdp_if_netstatus status;
	tdp_if_netstatus *new_status;

	sysmgr_trace_enter();

	status_size = 0;
	new_status = NULL;

	memset(&status, 0, sizeof(status));

	if (!mask_test_bit(dp_if->attr, eDP_IF_ATTR_NET)) {
		sysmgr_err("dp if[%s] do not have net attribute\n", dp_if->name);
		ret = eRET_INVALID_STATE;
		goto out;
	}

	ret = os_dep_get_if_mtu(dp_if->name, &status.mtu);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_get_if_mtu() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_get_if_ipaddr(dp_if->name, status.ipaddr);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_get_if_ipaddr() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_get_if_netmask(dp_if->name, status.netmask);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_get_if_netmask() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_get_default_gw(status.defaultgw);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_get_default_gw() failed, ret: %d\n", ret);
		goto out;
	}

	ret = os_dep_get_name_server(status.dns.dns1, status.dns.dns2);
	if (ret != eRET_SUCCESS) {
		sysmgr_err("os_dep_get_name_server() failed, ret: %d\n", ret);
		goto out;
	}

	/* Todo: get dhcp lease entries.  */
	status.dhcp_lease_counter = 0;

	status_size = sizeof(tdp_if_netstatus) + (status.dhcp_lease_counter * sizeof(tdhcp_lease_entry));
	new_status = malloc(status_size);
	if (new_status == NULL) {
		sysmgr_err("malloc(%d) failed, err: %d,[%s]\n", status_size, errno, strerror(errno));
		ret = eRET_NO_RESOURCE;
		goto out;
	}

	memcpy(new_status, &status, status_size);

out:
	*netstatus_size = status_size;
	*netstatus = new_status;
	sysmgr_trace_exit();
	return (ret);
}

e_ret dhcpc_svc_start(tsm_svc * svc)
{
	int rc;
	tdp_if_netcfg *if_netcfg;
	tdp_if *dp_if = (tdp_if *) svc->priv;

	if (dp_if == NULL) {
		sysmgr_err("System Service[%s], got NULL priv.\n", svc->name);
		return (eRET_INVALID_ARG);
	}

	if_netcfg = (tdp_if_netcfg *) dp_if->netcfg;
	if (if_netcfg == NULL) {
		sysmgr_err("if[%s], got NULL net config.\n", dp_if->name);
		return (eRET_INVALID_ARG);
	}

	os_dep_mutex_lock(&svc->mutex);

	svc->task = 0;

	os_dep_killall("udhcpc", "-SIGTERM");
	usleep(1000);
	/*
	 **  NOW: SVC -> task == 0,
	 **  So we can direct send Child signal to make sure process has been Reclaim.
	 **  It's a double check.
	 */
	os_dep_killall("sysmgr", "-SIGCHLD");
	usleep(1000);

	if (if_netcfg->man_dns) {
		rc = os_dep_do_system_raw(eBOOL_FALSE, &svc->task,
					  "udhcpc", "-f", "-H", PF_DEP_HOSTNAME, "-i", dp_if->name,
					  "-s", "/sbin/udhcpc_no_dns.script", NULL);
		sysmgr_dbg("os_dep_do_system_raw(udhcpc, no_dns), rc: %d\n", rc);
	} else {
		rc = os_dep_do_system_raw(eBOOL_FALSE, &svc->task,
					  "udhcpc", "-f", "-H", PF_DEP_HOSTNAME, "-i", dp_if->name,
					  "-s", "/sbin/udhcpc.script", NULL);
		sysmgr_dbg("os_dep_do_system_raw(udhcpc), rc: %d\n", rc);
	}
	os_dep_mutex_unlock(&svc->mutex);
	return (eRET_SUCCESS);
}

e_ret dpif_add_dhcpc_svc(tdp_if * dp_if)
{
	tsm_svc *dhcpc;
	char dhcpc_svc_name[SYSMGR_SERVICE_NAME_SIZE];

	sysmgr_trace_enter();

	dhcpc = NULL;
	sprintf(dhcpc_svc_name, SYSMGR_SVC_DHCPC_FORMAT, dp_if->name);
	svcmgr_find_svc(dhcpc_svc_name, &dhcpc);
	if (dhcpc == NULL) {
		dhcpc = malloc(sizeof(tsm_svc));
		if (dhcpc == NULL) {
			sysmgr_err("malloc(%d) failed, err: %d,[%s]\n", (sizeof(tsm_svc)), errno, strerror(errno));
			sysmgr_trace_exit();
			return (eRET_NO_RESOURCE);
		}
		memset(dhcpc, 0, sizeof(tsm_svc));
		os_dep_mutex_init(&dhcpc->mutex);
		strcpy(dhcpc->name, dhcpc_svc_name);
		dhcpc->enable = eBOOL_TRUE;
		dhcpc->start = dhcpc_svc_start;
		dhcpc->priv = (void *)dp_if;

		dhcpc_svc_start(dhcpc);

		svcmgr_add_svc(dhcpc);
	} else {
		os_dep_killall("udhcpc", "-SIGTERM");
		usleep(1000);
	}

	sysmgr_trace_exit();
	return (eRET_SUCCESS);

}

e_ret dpif_del_dhcpc_svc(tdp_if * dp_if)
{
	tsm_svc *dhcpc;
	char svc_name[SYSMGR_SERVICE_NAME_SIZE];

	sysmgr_trace_enter();

	sprintf(svc_name, SYSMGR_SVC_DHCPC_FORMAT, dp_if->name);

	svcmgr_find_svc(svc_name, &dhcpc);

	if (dhcpc != NULL) {
		svcmgr_del_svc(dhcpc);
		dhcpc->enable = eBOOL_FALSE;
		os_dep_mutex_destory(&dhcpc->mutex);
		free(dhcpc);
	}

	os_dep_killall("udhcpc", "-SIGTERM");
	usleep(1000);
	/*
	 **  NOW: SVC -> task == 0,
	 **  So we can direct send Child signal to make sure process has been Reclaim.
	 **  It's a double check.
	 */
	os_dep_killall("sysmgr", "-SIGCHLD");
	usleep(1000);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);
}
